<?php

class Board {

    public $cards;
    public $trash;
    public $prizes;
    public $allPrizesCards;
    public $embargoCards;
    public $tradeRouteCards;
    public $baneCards;
    public $blackMarketCards;
    public $allBlackMarketCards;
    public $spoilsCards;
    public $mercenaryCards;
    public $madmanCards;
    public $shelterCards;
    private $isDarkAges;

    public function __construct($cards = array(), $trash = array(), $prizes = array(), $embargoCards = array(), $tradeRouteCards = array(), $baneCards = array(), $blackMarketCards = array(), $allPrizesCards = array(), $allBlackMarketCards = array(), $spoilsCards = array(), $mercenaryCards = array(), $madmanCards = array(), $shelterCards = array()) {

        $this->cards = $cards;
        $this->trash = $trash;
        $this->embargoCards = $embargoCards;
        $this->tradeRouteCards = $tradeRouteCards;
        $this->baneCards = $baneCards;
        $this->prizes = $prizes;
        $this->blackMarketCards = $blackMarketCards;
        $this->allPrizesCards = $allPrizesCards;
        $this->allBlackMarketCards = $allBlackMarketCards;
        $this->spoilsCards = $spoilsCards;
        $this->mercenaryCards = $mercenaryCards;
        $this->madmanCards = $madmanCards;
        $this->shelterCards = $shelterCards;
    }

    public function getBoardData($game, $data = array()) {

        $data['board'] = array();
        $data['board']['trash'] = beautifyString(nicePrint($this->trash));
        $data['board']['prizes'] = getPileData($game, $this->prizes);
        $data['board']['kingdom'] = getQuantityPileData($game, $this->cards);
        $data['board']['embargo'] = getPileData($game, $this->embargoCards);
        if ($this->isCardOnBoard(new TradeRoute()))
            $data['board']['traderoute'] = getPileData($game, $this->tradeRouteCards);
        else
            $data['board']['traderoute'] = array();
        $data['board']['bane'] = getPileData($game, $this->baneCards);
        $data['board']['blackmarket'] = getPileData($game, $this->allBlackMarketCards);
        $data['board']['spoils'] = sizeof(getPileData($game, $this->spoilsCards));
        $data['board']['mercenary'] = sizeof(getPileData($game, $this->mercenaryCards));
        $data['board']['madman'] = sizeof(getPileData($game, $this->madmanCards));

        return $data;
    }

    public function isCardOnBoard($card) {
        foreach ($this->cards as $c) {
            $boardCard = $this->getCard($c);
            if ($boardCard->getKey() == $card->getKey()) {
                return true;
            }
        }
        return false;
    }

    private function addNewCard(Game $game, $card, $debugGame = false) {
        if (!$card->isImplemented() && !$debugGame)
            return false;

        $numOfPlayers = sizeof($game->getPlayersNames());
        $removeVictoryCards = 0;
        if ($numOfPlayers < 4) {
            $removeVictoryCards = 4;
        }

        $res = array();
        $res['card'] = $card;
        $res['subPile'] = array();

        if ($card instanceof Curse || $card instanceof iRuin)
            $res['quantity'] = max(10, ($numOfPlayers - 1) * 10);
        else if ($card instanceof Copper)
            $res['quantity'] = 60;
        else if ($card instanceof Silver)
            $res['quantity'] = 40;
        else if ($card instanceof Gold)
            $res['quantity'] = 30;
        else if ($card instanceof Potion || $card instanceof Platinum)
            $res['quantity'] = 12;
        else if ($card instanceof iVictory)
            $res['quantity'] = 12 - $removeVictoryCards;
        else if ($card instanceof Rats)
            $res['quantity'] = 20;
        else
            $res['quantity'] = 10;

        $this->cards[$card->getKey()] = $res;
        return true;
    }

    public function setNewBoard(Game $game, $decks, $required_cards, $all_cards, $forceColony, $forceDarkAges, $debugGame) {

        $this->cards = array();
        $this->addNewCard($game, new Curse());
        $this->addNewCard($game, new Copper());
        $this->addNewCard($game, new Silver());
        $this->addNewCard($game, new Gold());
        $this->addNewCard($game, new Estate());
        $this->addNewCard($game, new Duchy());
        $this->addNewCard($game, new Province());

        $i = 0;
        $numOfCards = 0;
        while ($numOfCards < 10 && $i < sizeof($required_cards)) {
            $card = n2c($required_cards[$i]);
            $card_added = $this->addNewCard($game, $card, $debugGame);
            if ($card_added)
                $numOfCards++;
            $i++;
        }

        if ($numOfCards < 10) {
            $all_cards_objects = array();
            foreach ($all_cards as $c) {
                $card = new $c;

                if (!$card->isImplemented() && !$debugGame)
                    continue;

                $isValidDeck = false;
                
                if (in_array('basic', $decks) && $card instanceof iBasic)
                    $isValidDeck = true;
                if (in_array('intrigue', $decks) && $card instanceof iIntrigue)
                    $isValidDeck = true;
                if (in_array('cornucopia', $decks) && $card instanceof iCornucopia)
                    $isValidDeck = true;
                if (in_array('prosperity', $decks) && $card instanceof iProsperity)
                    $isValidDeck = true;
                if (in_array('seaside', $decks) && $card instanceof iSeaside)
                    $isValidDeck = true;
                if (in_array('alchemy', $decks) && $card instanceof iAlchemy)
                    $isValidDeck = true;
                if (in_array('hinterlands', $decks) && $card instanceof iHinterlands)
                    $isValidDeck = true;
                if (in_array('darkages', $decks) && $card instanceof iDarkAges)
                    $isValidDeck = true;
                if (in_array('addiction', $decks) && $card instanceof iAddiction)
                    $isValidDeck = true;
                if (in_array('promotion', $decks) && $card instanceof iPromotion)
                    $isValidDeck = true;
                 if (in_array('guilds', $decks) && $card instanceof iGuilds)
                    $isValidDeck = true;


                if ($isValidDeck)
                    $all_cards_objects[] = $card;
            }

            if (sizeof($all_cards_objects) < 10) {
                return false;
            }

            while ($numOfCards < 10) {
                $card = $all_cards_objects[rand(0, sizeof($all_cards_objects) - 1)];
                if (!array_key_exists($card->getKey(), $this->cards) &&
                        !array_key_exists($card->getKey(), $this->blackMarketCards)) {
                    $card_added = $this->addNewCard($game, $card, $debugGame);
                    if ($card_added)
                        $numOfCards++;
                }
            }
        }

        //go over the cards and activate special setup for each card
        foreach ($this->cards as $card_arr) {
            $card = $card_arr['card'];
            $card->boardSetup($game);
            foreach ($card_arr['subPile'] as $subPileCard) {
                $subPileCard->boardSetup($game);
            }
        }

        $prosperityFlag = 0;
        $darkAgesFlag = 0;
        foreach ($this->cards as $card_arr) {
            $card = $card_arr['card'];
            if ($card instanceof iProsperity && $card instanceof iKingdom) {
                $prosperityFlag++;
            }
            if ($card instanceof iDarkAges && $card instanceof iKingdom) {
                $darkAgesFlag++;
            }
        }

        if (rand(1, 10) <= $prosperityFlag || $forceColony) {
            $this->addNewCard($game, new Platinum);
            $this->addNewCard($game, new Colony());
        }

        $this->isDarkAges = false;
        if (rand(1, 10) <= $darkAgesFlag || $forceDarkAges) {
            $this->shelterCards[] = new OvergrownEstate();
            $this->shelterCards[] = new Hovel;
            $this->shelterCards[] = new Necropolis();
            $this->isDarkAges = true;
        }

        return true;
    }

    public function isDarkAges() {
        return $this->isDarkAges;
    }

    public function addPotion(Game $game) {
        $this->addNewCard($game, new Potion());
    }

    public function addSpoils(Game $game) {
        if (sizeof($this->spoilsCards) == 0) {
            $spoils_arr = array();
            $spoils = new Spoils();
            for ($i = 0; $i < 15; $i+=1) {
                $spoils_arr[] = $spoils;
            }
            $this->spoilsCards = $spoils_arr;
        }
        return true;
    }

    public function addPrizes(Game $game) {
        $this->prizes = array(new BagOfGold(), new Diadem(), new Followers(), new Princess, new TrustySteed(), new Duchy());
        $this->allPrizesCards = $this->prizes;
    }

    public function addMercenary() {
        if (sizeof($this->mercenaryCards) == 0) {
            $mer_arr = array();
            $mercenary = new Mercenary();
            for ($i = 0; $i < 10; $i+=1) {
                $mer_arr[] = $mercenary;
            }
            $this->mercenaryCards = $mer_arr;
        }
        return true;
    }

    public function addMadman() {
        if (sizeof($this->madmanCards) == 0) {
            $mad_arr = array();
            $madman = new Madman();
            for ($i = 0; $i < 10; $i+=1) {
                $mad_arr[] = $madman;
            }
            $this->madmanCards = $mad_arr;
        }
        return true;
    }

    public function addKnights(Game $game) {

        $knights = new Knights();

        $this->addNewCard($game, $knights);

        $knights = array();
        $knights[] = new DameAnna();
        $knights[] = new DameJosephine();
        $knights[] = new DameMolly();
        $knights[] = new DameNatalie();
        $knights[] = new DameSylvia();
        $knights[] = new SirBailey();
        $knights[] = new SirDestry();
        $knights[] = new SirMartin();
        $knights[] = new SirMichael();
        $knights[] = new SirVander();
        shuffle($knights);
        $this->cards['Knights']['subPile'] = $knights;
    }

    public function addRuins(Game $game) {
        $ruin = new Ruin();
        if (!array_key_exists($ruin->getKey(), $this->cards)) {
            $this->addNewCard($game, $ruin);
            $numOfPlayers = sizeof($game->getPlayersNames());
            $quantity = max(10, ($numOfPlayers - 1) * 10);

            $ab = new AbandonedMine();
            $rl = new RuinedLibrary();
            $rm = new RuinedMarket();
            $rv = new RuinedVillage();
            $su = new Survivors();
            $ruins = array();
            for ($i = 0; $i < 10; $i+=1) {
                $ruins[] = $ab;
                $ruins[] = $rl;
                $ruins[] = $rm;
                $ruins[] = $rv;
                $ruins[] = $su;
            }
            shuffle($ruins);
            $ruins = array_slice($ruins, 0, $quantity);
            $this->cards[$ruin->getKey()]['subPile'] = $ruins;
        }
    }

    public function addBaneCard(Game $game) {

        $min_price = new Price(2);
        $max_price = new Price(3);
        while (True) {
            $bane_card_name = Game::$ALL_KINGDOM[rand(0, sizeof(Game::$ALL_KINGDOM) - 1)];
            $bane_card = new $bane_card_name;
            $price = $bane_card->getPrice($game);
            if ($price->compare($min_price) >= 0 && $price->compare($max_price) <= 0) {
                if (!array_key_exists($bane_card->getKey(), $this->cards) &&
                        !array_key_exists($bane_card->getKey(), $this->blackMarketCards)) {

                    if (!$bane_card->isActualCard())
                        continue;

                    $card_added = $this->addNewCard($game, $bane_card);
                    if (!$card_added)
                        continue;

                    $this->baneCards[] = $bane_card;
                    $bane_card->boardSetup($game);
                    break;
                }
            }
        }
    }

    public function addBlackMarket(Game $game) {
        $i = 0;
        while ($i < 20) {
            $blackmarket_card_name = Game::$ALL_KINGDOM[rand(0, sizeof(Game::$ALL_KINGDOM) - 1)];
            $blackmarket_card = new $blackmarket_card_name;
            if (!$blackmarket_card->isImplemented())
                continue;
            if (!$blackmarket_card->isActualCard())
                continue;
            if (!array_key_exists($blackmarket_card->getKey(), $this->cards) &&
                    !array_key_exists($blackmarket_card->getKey(), $this->blackMarketCards)) {

                $this->blackMarketCards[$blackmarket_card->getKey()] = $blackmarket_card;
                $blackmarket_card->boardSetup($game);
                $i++;
            }
        }
        $this->allBlackMarketCards = $this->blackMarketCards;
        foreach ($this->blackMarketCards as $card) {
            $this->allBlackMarketCards[$card->getKey()] = $card;
        }
        ksort($this->allBlackMarketCards);
    }

    public function save($gid) {
        $this->saveQuantityPileHelper($gid, 'board', $this->cards);
        $this->savePileHelper($gid, 'trash', $this->trash);
        $this->savePileHelper($gid, 'prizes', $this->prizes);
        $this->savePileHelper($gid, 'embargo', $this->embargoCards);
        $this->savePileHelper($gid, 'traderoute', $this->tradeRouteCards);
        $this->savePileHelper($gid, 'bane', $this->baneCards);
        $this->savePileHelper($gid, 'blackmarket', $this->blackMarketCards);
        $this->savePileHelper($gid, 'allprizes', $this->allPrizesCards);
        $this->savePileHelper($gid, 'allblackmarket', $this->allBlackMarketCards);
        $this->savePileHelper($gid, 'spoils', $this->spoilsCards);
        $this->savePileHelper($gid, 'mercenary', $this->mercenaryCards);
        $this->savePileHelper($gid, 'madman', $this->madmanCards);
        $this->savePileHelper($gid, 'shelter', $this->shelterCards);
        return true;
    }

    private function saveQuantityPileHelper($gid, $type, $pile) {
        $db = DBUtils::Create();
        $cs = "";
        foreach ($pile as $card) {
            $cs .= $card['card']->getKey() . "~" . $card['quantity'] . "~";
            foreach ($card['subPile'] as $subPileCard) {
                $cs.= $subPileCard->getKey() . "~";
            }

            $cs .="|";
        }

        $cs = substr($cs, 0, strlen($cs) - 1);
        $db->savePile($gid, 0, $type, $cs);
    }

    private function savePileHelper($gid, $type, $pile) {
        $db = DBUtils::Create();
        $cs = "";
        foreach ($pile as $card) {
            $cs .= $card->getKey() . "|";
        }
        $cs = substr($cs, 0, strlen($cs) - 1);
        $db->savePile($gid, 0, $type, $cs);
    }

    public function getBaneCard() {
        return $this->baneCards[0];
    }

    public function embargoCard($card) {
        array_unshift($this->embargoCards, $card);
        return $card;
    }

    public function getEmbargoedCards() {
        return $this->embargoCards;
    }

    public function addCardToTradeRoute($card) {
        array_unshift($this->tradeRouteCards, $card);
        return $card;
    }

    public function getTradeRouteCards() {
        return $this->tradeRouteCards;
    }

    public function getCardFromPile($card, $srcPile) {
        switch ($srcPile) {
            case BoardCards:
                return $this->getCardFromBoard($card);
            case Trash:
                return $this->getCardFromTrash($card);
            case Prizes:
                return $this->getCardFromPrizes($card);
            case BlackMarketPile:
                return $this->getCardFromBlackMarket($card);
            case Spoils:
                return $this->getCardFromSpoils();
            case Ruins:
                return $this->getCardFromRuins();
            case Mercenary:
                return $this->getCardFromMercenary();
            case Madman:
                return $this->getCardFromMadman();
            default:
                throw new Exception("Not a valid pile " . $srcPile);
        }
    }

    public function putCardtoPile($card, $dstPile) {
        switch ($dstPile) {
            case BoardCards:
                return $this->putCardToBoard($card);
            case Trash:
                return $this->putCardInTrash($card);
            case Spoils:
                return $this->putCardInSpoils($card);
            case Madman:
                return $this->putCardInMadman($card);
            case Mercenary:
                return $this->putCardInMercenary($card);
            case Prizes:
                return $this->putCardInPrizes($card);
            default:
                throw new Exception("Not a valid pile " . $srcPile);
        }
    }

    public function getCardFromTrash($card) {
        $found = false;
        $card_index = -1;
        foreach ($this->trash as $c) {
            $card_index += 1;
            if ($c->getKey() == $card->getKey()) {
                $found = true;
                break;
            }
        }
        if (!$found) {
            return null;
        }
        array_splice($this->trash, $card_index, 1);
        return $card;
    }

    public function getCardFromPrizes($card) {
        $found = false;
        $card_index = -1;
        foreach ($this->prizes as $c) {
            $card_index += 1;
            if ($c->getKey() == $card->getKey()) {
                $found = true;
                break;
            }
        }
        if (!$found) {
            return null;
        }
        array_splice($this->prizes, $card_index, 1);
        return $card;
    }

    public function getCardFromMercenary() {
        if (sizeof($this->mercenaryCards) == 0)
            return null;

        $card = $this->mercenaryCards[0];
        array_splice($this->mercenaryCards, 0, 1);
        return $card;
    }

    public function getCardFromMadman() {
        if (sizeof($this->madmanCards) == 0)
            return null;

        $card = $this->madmanCards[0];
        array_splice($this->madmanCards, 0, 1);
        return $card;
    }

    public function getCardFromSpoils() {
        if (sizeof($this->spoilsCards) == 0)
            return null;

        $card = $this->spoilsCards[0];
        array_splice($this->spoilsCards, 0, 1);
        return $card;
    }

    public function getCardFromBlackMarket($card) {
        $found = false;
        $card_index = -1;
        $bmCard = null;
        foreach ($this->blackMarketCards as $c) {
            $card_index += 1;
            if ($c->getKey() == $card->getKey()) {
                $found = true;
                $bmCard = $c;
                break;
            }
        }
        if (!$found) {
            return null;
        }
        array_splice($this->blackMarketCards, $card_index, 1);
        return $bmCard;
    }
    
    public function peekCardFromBlackMarket($card) {
        $found = false;
        $bmCard = null;
        foreach ($this->blackMarketCards as $c) {
            if ($c->getKey() == $card->getKey()) {
                $found = true;
                $bmCard = $c;
                break;
            }
        }
        if (!$found) {
            return null;
        }
        return $bmCard;
    }

    public function getCardFromBoard($card) {
        $found = false;
        $card_index = -1;
        foreach ($this->cards as $c) {
            $card_index += 1;
            $boardCard = $this->getCard($c);
            if ($boardCard->getKey() == $card->getKey() || $c['card']->getKey() == $card->getKey()) {
                if ($c['quantity'] == 0) {
                    return null;
                }
                $found = true;
                break;
            }
        }
        if (!$found) {
            return null;
        }

        $card_arr = $this->cards[$card_index];
        $card_arr['quantity'] -= 1;

        if (sizeof($card_arr['subPile']) > 0) {
            $res = $card_arr['subPile'][0];
            array_shift($card_arr['subPile']);
            $this->cards[$card_index] = $card_arr;
            return $res;
        } else {
            $this->cards[$card_index] = $card_arr;
            return $card_arr['card'];
        }
    }

    public function putCardToBoard($card) {
        $found = false;
        $card_index = -1;

        $card_class = $card->getKey();
        if ($card instanceof iRuin) {
            $r = new Ruin();
            $card_class = $r->getKey();
        }
        if ($card instanceof iKnight) {
            $k = new Ruin();
            $card_class = $k->getKey();
        }
        foreach ($this->cards as $c) {
            $card_index += 1;
            if ($c['card']->getKey() == $card_class) {
                $found = true;
                break;
            }
        }
        if (!$found) {
            #in case the user returns a card that not on board - like blackmarket - ambassador example
            return $card;
            //throw new Exception("card not found on the board " . $card->getValue());
        }

        $card_arr = $this->cards[$card_index];
        $card_arr['quantity']++;
        array_unshift($card_arr['subPile'], $card);
        $this->cards[$card_index] = $card_arr;
        return $card;
    }

    public function removeTopBlackMarketCards($num) {
        $res = array();
        for ($i = 0; $i < $num; $i++) {
            if (sizeof($this->blackMarketCards) > 0) {
                $card = array_shift($this->blackMarketCards);
                $res[] = $card;
            }
        }
        return $res;
    }

    public function putCardOnBottomOfBlackMarket($card) {
        $this->blackMarketCards[] = $card;
    }

    public function getTrash() {
        return $this->trash;
    }

    public function getPrizes() {
        return $this->prizes;
    }

    public function peekCard($card) {

        $found = false;
        $card_index = -1;
        foreach ($this->cards as $c) {
            $card_index += 1;
            $boardCard = $this->getCard($c);
            if ($boardCard->getKey() == $card->getKey()) {
                if ($c['quantity'] == 0) {
                    return null;
                }
                $found = true;
                break;
            }
        }
        if (!$found) {
            throw new Exception("card not found on the board " . $card->getValue());
            return null;
        }

        $card = $this->getCard($this->cards[$card_index]);
        return $card;
    }

    public function setPriceForCard($card, $price) {
        foreach ($this->cards as $bc) {
            if ($bc['card']->getKey() == $card->getKey()) {
                $bc['card']->setPrice($price);
                foreach ($bc['subPile'] as $subPileCard) {
                    $subPileCard->setPrice($price);
                }
            }
            foreach ($bc['subPile'] as $subPileCard) {
                if ($subPileCard->getKey() == $card->getKey()) {
                    $subPileCard->setPrice($price);
                }
            }
        }
    }

    public function putCardInSpoils($card) {
        array_unshift($this->spoilsCards, $card);
        return $card;
    }

    public function putCardInMercenary($card) {
        array_unshift($this->mercenaryCards, $card);
        return $card;
    }

    public function putCardInPrizes($card) {
        array_unshift($this->prizes, $card);
        return $card;
    }

    public function putCardInMadman($card) {
        array_unshift($this->madmanCards, $card);
        return $card;
    }

    public function putCardInTrash($card) {
        array_unshift($this->trash, $card);
        return $card;
    }

    public function getAllBoardCards($getVirtualCards = false, $withBlackMarket = true) {
        $res = array();

        foreach ($this->cards as $card_arr) {

            if (sizeof($card_arr['subPile']) > 0) {
                foreach ($card_arr['subPile'] as $subCard) {
                    $res[$subCard->getKey()] = $subCard;
                }
                if ($getVirtualCards) {
                    $res[$card_arr['card']->getKey()] = $card_arr['card'];
                }
            } else {
                $card = $this->getCard($card_arr);
                $res[$card->getKey()] = $card;
            }
        }
        foreach ($this->trash as $card) {
            $res[$card->getKey()] = $card;
        }
        foreach ($this->allPrizesCards as $card) {
            $res[$card->getKey()] = $card;
        }
        if ($withBlackMarket) {
            foreach ($this->allBlackMarketCards as $card) {
                $res[$card->getKey()] = $card;
            }
        }
        foreach ($this->spoilsCards as $card) {
            $res[$card->getKey()] = $card;
        }
        foreach ($this->madmanCards as $card) {
            $res[$card->getKey()] = $card;
        }
        foreach ($this->mercenaryCards as $card) {
            $res[$card->getKey()] = $card;
        }
        foreach ($this->shelterCards as $card) {
            $res[$card->getKey()] = $card;
        }

        return $res;
    }

    private function getCard($card_arr) {
        if (sizeof($card_arr['subPile']) > 0) {
            return $card_arr['subPile'][0];
        }
        return $card_arr['card'];
    }

    public function getAllBoardCardsByPrice($game, $min_price, $max_price) {
        $res = array();
        foreach ($this->cards as $card_arr) {
            $card = $this->getCard($card_arr);
            $price = $card->getPrice($game);
            if ($price->compare($min_price) >= 0 &&
                    $price->compare($max_price) <= 0) {
                $res[] = $this->getCard($card_arr);
            }
        }
        return $res;
    }

    public function getTrashCardsByPrice($game, $min_price, $max_price) {
        $res = array();
        foreach ($this->trash as $card) {
            $price = $card->getPrice($game);

            if ($price->compare($min_price) >= 0 &&
                    $price->compare($max_price) <= 0) {
                $res[] = $card;
            }
        }
        return $res;
    }

    public function getAllBoardIncludingEmptyPiles($game, $includeBlackMarket = false) {
        $res = array();
        foreach ($this->cards as $card_arr) {
            $card = $this->getCard($card_arr);
            $res[] = $card;
        }
        if ($includeBlackMarket) {
            foreach ($this->blackMarketCards as $card) {
                $res[] = $card;
            }
        }
        return $res;
    }

    public function getBoardCardsByPrice($game, $min_price, $max_price) {
        $res = array();
        foreach ($this->cards as $card_arr) {
            $card = $this->getCard($card_arr);
            $price = $card->getPrice($game);

            if ($card_arr['quantity'] > 0 &&
                    $price->compare($min_price) >= 0 &&
                    $price->compare($max_price) <= 0) {
                $res[] = $card;
            }
        }
        return $res;
    }

    public function getBoardTreasureCardsByPrice($game, $min_price, $max_price) {
        $res = array();
        foreach ($this->cards as $card_arr) {
            $card = $this->getCard($card_arr);
            $price = $card->getPrice($game);
            if ($card_arr['quantity'] > 0 &&
                    $price->compare($min_price) >= 0 &&
                    $price->compare($max_price) <= 0 &&
                    $card instanceof iTreasure) {

                $res[] = $card;
            }
        }
        return $res;
    }

    public function getBoardVictoryCardsByPrice($game, $min_price, $max_price) {
        $res = array();
        foreach ($this->cards as $card_arr) {
            $card = $this->getCard($card_arr);
            $price = $card->getPrice($game);
            if ($card_arr['quantity'] > 0 &&
                    $price->compare($min_price) >= 0 &&
                    $price->compare($max_price) <= 0 &&
                    $card instanceof iVictory) {

                $res[] = $card;
            }
        }
        return $res;
    }

    public function getBoardActionCardsByPrice($game, $min_price, $max_price) {
        $res = array();
        foreach ($this->cards as $card_arr) {
            $card = $this->getCard($card_arr);
            $price = $card->getPrice($game);
            if ($card_arr['quantity'] > 0 &&
                    $price->compare($min_price) >= 0 &&
                    $price->compare($max_price) <= 0 &&
                    $card instanceof iAction) {

                $res[] = $card;
            }
        }
        return $res;
    }

    public function getTopBlackMarketCards($num) {
        $i = 0;
        $res = array();
        while ($i < sizeof($this->blackMarketCards) && $i < $num) {
            $res[] = $this->blackMarketCards[$i];
            $i++;
        }
        return $res;
    }

    private function getEmptyPiles() {
        $emptypiles = array();
        foreach ($this->cards as $card_arr) {
            if ($card_arr['quantity'] == 0) {
                $emptypiles[] = $card_arr['card'];
            }
        }
        return $emptypiles;
    }

    public function numberOfEmptyPiles() {
        return sizeof($this->getEmptyPiles());
    }

    public function isGameOver() {
        $emptyPiles = $this->getEmptyPiles();
        $numOfEmptyPiles = sizeof($emptyPiles);

        if ($numOfEmptyPiles >= 3)
            return true;

        $province = new Province();
        $colony = new Colony();
        foreach ($emptyPiles as $card) {
            if ($card->getKey() == $province->getKey() || $card->getKey() == $colony->getKey())
                return true;
        }

        return false;
    }

}

?>